﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using static ShowCat.KeyBoardHook;

namespace ShowCat
{
    public partial class Form1 : Form
    {
        System.Timers.Timer fadeStartTimer = new System.Timers.Timer();
        FadeAnimation fadeAnimation;
        [DllImport("user32.dll")]
        private static extern int SendMessage(IntPtr hwnd, int msg, int wParam, int lParam);
        private KeyBoardHook hook = new KeyBoardHook();
        private const int WM_USER = 0x0400;
        private const int WM_KEYDOWN = 0x0100;
        private const int WM_KEYUP = 0x0101;
        static String[] mapper =
        {
            "","LBUTTON","RBUTTON","VK_CANCEL","VK_MBUTTON","VK_XBUTTON1","VK_XBUTTON2","_","Backspace","Tab","_","_","Clear","Enter","_","_",  // 0x0F
            "Shift","Ctrl","Alt","Pause","CapsLk","KANA","HANGUEL","HANGUL","IME_ON","JUNJA","FINAL","ESC","_","_", "_","_",// 0x10
            "Space","PageUP","PageDown","End","Home","Left","Up","Right","Down","SELECT","PRINT","EXECUTE","PrtSc","Ins","del","Help", //20
            "0","1","2","3","4","5","6","7","8","9","_","_","_","_","_","_","_",     // 0x30
            "A","B", "C","D","E","F","G","H","I","J","K","L","M","N","O",    // 0x40
            "P","Q","R","S","T","U","V","W","S","Y","Z","Win","Win","App","Sleep","Sleep",  // 0x50
            "Num0","Num1","Num2","Num3","Num4","Num5","Num6","Num7","Num8","Num9","*","+","Sptor","-","Num.","/", // 0x60
            "F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12","F13","F14","F15","F16",
            "F17","F18","F19","F20","F21","F22","F23","F24","_","_","_","_","_","_","_","_",  // 0x80
            "NumLk","ScrLk","_","_","_","_","_","_","_","_","_","_","_","_","_","_", //0x90
            "LShift","RShift","LCtrl","RCtrl","LAlt","RMenu","Browser Back","Browser Forward","Browser Refresh","Browser Stop","Browser Search","Browser Favorites","Browser Start","Volume Mute","Volume Down","Volume Up", // 0xA0
            "Next Track","Previous Track","Stop Media","Play/Pause","Start Mail","Select Media","Start Application 1","Start Application 2","_","_",";","=",",","-",".","/", // 0xB0
            "`","_","_","_","_","_","_","_","_","_","_","_","_","_","_","_", // 0xC0
            "_","_","_","_","_","_","_","_","_","_","_","[","\\","]","'","_","_" // 0xD0
        };
        static HashSet<int> keysPressed =  new HashSet<int>();
        private static String ScanCode2String(int scanCode)
        {
            
            if (scanCode < mapper.Length)
            {
                return mapper[scanCode];
            }
            return " ";
        }
        private void KeyBoardHandle(HookStruct param, out bool handle)
        {
            handle = false;
            SendMessage(Handle, WM_USER,param.dwExtraInfo,param.vkCode);
        }
        public Form1()
        {
            
            InitializeComponent();
            fadeStartTimer.Interval = 600;
            fadeStartTimer.AutoReset = false;
            fadeStartTimer.Elapsed += doFadeStartTimer;
            fadeAnimation = new FadeAnimation(this, 400, clear);
        }
        private void clear()
        {
            keysPressed.Clear();
            label1.Text = "";
        }
        private void doFadeStartTimer(object sender, System.Timers.ElapsedEventArgs e)
        {
            this.AllowTransparency = true;
            fadeAnimation.startAnimat();
        }

        private void Load_(object sender, EventArgs e)
        {
            hook.InstallHook(KeyBoardHandle);
            Point ld = new Point(0, Screen.PrimaryScreen.Bounds.Height - this.Height);
            this.Location = ld;
        }

        private void doKeysEvents(ref Message m)
        {   
            if (m.WParam.ToInt32() == WM_KEYDOWN)
            {
                if (fadeStartTimer.Enabled)
                {
                    fadeStartTimer.Stop();
                    fadeStartTimer.Start();
                } else if (!fadeStartTimer.Enabled)
                {
                    fadeStartTimer.Start();
                }
                if(fadeAnimation.Isplaying()) {
                    fadeAnimation.CancelAnimat();
                }
                keysPressed.Add(m.LParam.ToInt32());
                RenderStroke();

            }
            else
            {
                keysPressed.Remove(m.LParam.ToInt32());
            }
        }

        private void RenderStroke()
        {
            String[] keyStr = new string[keysPressed.Count];
            int idx = 0;
            foreach (int scanCode in keysPressed)
            {
                keyStr[idx++] = ScanCode2String(scanCode);
            }
            if (keyStr.Length == 0)
            {
                label1.Text = "";
                return;
            }
            StringBuilder sb = new StringBuilder();
            sb.Append(keyStr[0]);
            if (keyStr.Length > 1)
            {
                for (int i = 1; i < keyStr.Length;++i)
                {
                    sb.Append("+");
                    sb.Append(keyStr[i]);
                }
            }
            label1.Text = sb.ToString();
        }

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_USER:
                    doKeysEvents(ref m);
                    break;
            }
            base.WndProc(ref m);
        }

        private void ClearUp(object sender, FormClosingEventArgs e)
        {
            hook.UninstallHook();
        }
    }
}
